package com.example.content.viewmodule

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.content.App
import com.example.content.R
import com.example.content.viewmodule.state.BaseViewState
import com.example.content.viewmodule.viewdata.BaseViewData
import com.example.core.extensions.showToast
import com.google.gson.JsonParseException
import kotlinx.coroutines.*
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketException
import java.net.UnknownHostException

typealias Block<T> = suspend () -> T
typealias Error = suspend (e: Exception) -> Unit
typealias Cancel = suspend (e:Exception) -> Unit
/**
 * Created by zhudongao
 * Desc
 * Date 2020/9/21
 */
open class BaseViewModel<VD:BaseViewData<in BaseViewState>> : ViewModel() {

    protected fun launch(
        block:Block<Unit>,
        error:Error? = null,
        cancel: Cancel? = null,
        showErrorToast:Boolean = true
    ):Job {
        return viewModelScope.launch {
            try {
                block.invoke()
            } catch (e: Exception) {
                Log.e("viewModuleException", "exception begin : " + e)
                onException()
                when (e) {
                    is CancellationException -> {
                        cancel?.invoke(e)
                    }
                    else -> {
                        onError(e, showErrorToast)
                        error?.invoke(e)
                    }
                }
            }
        }
    }

    open fun onException() {

    }

    protected fun <T> async(block: Block<T>): Deferred<T> {
        return viewModelScope.async { block.invoke() }
    }

    /**
     * 取消协程
     * @param job 协程job
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }

    private fun onError(e: Exception, showErrorToast: Boolean) {
        when (e) {
            //todo api 错误识别
            is ConnectException, is SocketException, is UnknownHostException, is HttpException -> {
                if (showErrorToast) App.appContext.showToast(R.string.network_request_failed)
            }
            // 数据解析错误
            is JsonParseException ->
                if (showErrorToast) App.appContext.showToast(R.string.api_data_parse_error)
            // 其他错误
            else ->
                if (showErrorToast) App.appContext.showToast(e.message ?: return)
        }
    }

    companion object {
        val TAG = BaseFuncViewModel::class.java.simpleName
    }
}